﻿using System;
using System.Reflection;
using System.Reflection.Emit;

namespace MyBasicLib.Reflection.FastReflection.Emit
{
    public class FieldAccessor : IFieldAccessor
    {
        private Func<object, object> m_getter;

        // public FieldInfo FieldInfo { get; private set; }

        public FieldAccessor(FieldInfo fieldInfo)
        {
            //    this.FieldInfo = fieldInfo;
            InitializeGet(fieldInfo);
        }

        #region IFieldAccessor Members

        object IFieldAccessor.GetValue(object instance)
        {
            return GetValue(instance);
        }

        #endregion

        private void InitializeGet(FieldInfo fieldInfo)
        {
            Type t = fieldInfo.DeclaringType;
            var dm = new DynamicMethod(string.Empty,
                                       typeof (object), new[] {typeof (object)}, t);
            ILGenerator il = dm.GetILGenerator();
            // Load the instance of the object (argument 0) onto the stack

            il.Emit(OpCodes.Ldarg_0);
            // Load the value of the object's field (fi) onto the stack

            il.Emit(OpCodes.Ldfld, fieldInfo);
            // return the value on the top of the stack
            if (fieldInfo.FieldType.IsValueType)
                il.Emit(OpCodes.Box, fieldInfo.FieldType);
            il.Emit(OpCodes.Ret);

            m_getter = dm.CreateDelegate(typeof (Func<object, object>)) as Func<object, object>;
        }

        public object GetValue(object instance)
        {
            return m_getter(instance);
        }
    }
}